﻿using Domain.Config;
using Domain.Event;
using Domain.IRepositorys;
using Domain.Model;
using Domain.Types;
using Infrastructure.AggregateBase;
using Infrastructure.Cache;
using Infrastructure.Error;
using Infrastructure.UniOfWorkBase;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using Utility;

namespace Domain.Services
{
    public class UserService : IService
    {
        public ISmsCodeRepository smsCodeRepository { get; set; }
        public IUserRepository userRepository { get; set; }
        public IBlackListRepository blackListRepository { get; set; }
        public ILoginLogRepository userLoginRepository { get; set; }
        public IEFUnitOfWork efUnitOfWork { get; set; }
        public WalletService walletService { get; set; }
        public IMemoryCacheService memoryCacheService { get; set; }


        const string RegisterKey = "UserRegister:";
        public (JwtSecurityToken, UserInfoAggregate) UserRegister(string phone, string registerToken, string code, LoginLogAggregate loginLog)
        {
            if (string.IsNullOrWhiteSpace(code))
            {
                code = "EXORG123";
            }

            var mtoken = memoryCacheService.Get<string>(RegisterKey + phone);
            if (string.IsNullOrWhiteSpace(mtoken)) throw new BizException("注册超时，请稍后重试!");
            if (registerToken != mtoken) throw new BizException("注册失败，请联系管理员!");

            var u = Register(phone, code);
            efUnitOfWork.Commit();
            efUnitOfWork.Reset();

            u.LastLoginTime = DateTime.Now;

            loginLog.UserID = u.ID;
            userLoginRepository.Insert(loginLog);

            efUnitOfWork.Commit();

            return (CreateToken(u), u);
        }

        public (JwtSecurityToken, UserInfoAggregate) Login(string phone, string phoneCode, LoginLogAggregate loginLog)
        {
            if (phoneCode != "1234")
            {


#if !DEBUG
            var code = smsCodeRepository.Entities.FirstOrDefault(i => i.Phone == phone&&i.SmsCodeType==SmsCodeType.登录注册 && i.SmsCode == phoneCode);

            if (code == null)
            {
                throw new BizException("手机验证码不正确");
            }
            code.Valid();
            code.IsUse = true;
#endif
            }

            var u = userRepository.Entities.FirstOrDefault(i => i.Phone == phone);

            if (u == null)
            {
                var token = Guid.NewGuid().ToString("N");

                memoryCacheService.Set<string>(RegisterKey + phone, token, TimeSpan.FromHours(2));

                throw new NotRegisterException($"用户未注册！", dic =>
                {
                    dic.Add("registerToken", token);
                });
                //u = Register(phone);
                //efUnitOfWork.Commit();
                //efUnitOfWork.Reset();
            }
            var bl = blackListRepository.Entities.FirstOrDefault(i => i.UserID == u.ID && i.BlackListPermissions.HasFlag(BlackListPermissions.禁止登录) && !i.IsDelete);
            if (bl != null)
            {
                string rtime = bl.RestoreTime != null ? bl.RestoreTime.Value.AddDays(1).ToString("禁止登录到yyyy-MM-dd为止") : "禁止登录到永远";
                throw new BizException($"你被管理员列入黑名单列表中,{rtime}！");
            }

            u.LastLoginTime = DateTime.Now;

            loginLog.UserID = u.ID;
            userLoginRepository.Insert(loginLog);

            efUnitOfWork.Commit();

            return (CreateToken(u), u);
        }


        public UserInfoAggregate Register(string phone, string code = "EXORG123")
        {
            UserInfoAggregate userInfoAggregate = new UserInfoAggregate();

            userInfoAggregate.LastLoginTime = DateTime.Now;
            userInfoAggregate.Phone = phone;

            var newcode = string.Empty;

            do
            {
                newcode = RandomUtil.GetRandomString(8);
            }
            while (userRepository.Entities.Any(i => i.InviteCode == newcode));

            userInfoAggregate.InviteCode = newcode;

            //设置上级
            var superorUser = userRepository.Entities.FirstOrDefault(i => i.InviteCode == code);
            if (superorUser == null) throw new BizException("您输的的邀请码不正确!");

            userInfoAggregate.SetSuperor(superorUser);

            userInfoAggregate.AddDomainEvent(new UserRegisterEvent()
            {
                Phone = phone,
                SuperorCode = code
            });

            userInfoAggregate = userRepository.Insert(userInfoAggregate);

            return userInfoAggregate;
        }
        public JwtSecurityToken Refresh(string tokenStr)
        {
            var token = new JwtSecurityToken(tokenStr);

            if (token.ValidTo.AddDays(15) < DateTime.Now)
            {
                throw new BizException("您的登录已过期,请重新登录!");
            }

            var ID = token.Claims.FirstOrDefault(i => i.Type == "ID").Value;

            var u = userRepository.GetByKey(int.Parse(ID));

            if (u == null)
            {
                throw new BizException("用户名不存在或密码输入错误!");
            }

            return CreateToken(u);
        }

        public JwtSecurityToken CreateToken(UserInfoAggregate u)
        {
            var authClaims = new[] {
                new Claim("ID",u.ID.ToString()),
                new Claim("NickName",u.NickName??""),
                new Claim("HeadImg",u.HeadImg??""),
                new Claim("UserLevel",u.UserLevel.ToString()),
                new Claim("TraderLevel",u.TraderLevel.ToString()),
                new Claim("SuperorID",u.SuperorID.ToString()),
                new Claim("InviteCode",u.InviteCode??""),
                new Claim("LastLoginTime",u.LastLoginTime?.ToString("yyyy-MM-dd HH:mm:ss")),
                new Claim(JwtRegisteredClaimNames.Iat,DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                new Claim(JwtRegisteredClaimNames.Sub,u.Phone),
                new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()),
                new Claim(JwtRegisteredClaimNames.Exp,DateTime.Now.AddHours(2).ToString("yyyy-MM-dd HH:mm:ss"))
            };

            IdentityModelEventSource.ShowPII = true;

            var token = new JwtSecurityToken(
                   issuer: Infrastructure.Config.ApiJwtConfig.ApiIssuer,
                   audience: Infrastructure.Config.ApiJwtConfig.ApiAudience,
                   expires: DateTime.Now.AddHours(2),
                   claims: authClaims,
                   signingCredentials: new SigningCredentials(
                       new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Infrastructure.Config.ApiJwtConfig.ApiSecureKey)), SecurityAlgorithms.HmacSha256)
                   );

            return token;

        }
        public IWalletRepository walletRepository { get; set; }


        public TraderLevelLog PayUpLevelByTrader(int uid, int month, int payID, int fee)
        {
            var wallet = walletRepository.Entities.FirstOrDefault(i => i.UserID == uid);
            if (wallet == null) throw new BizException($"未找到用户钱包！");


            if (wallet.ChargeBlance < fee) throw new BizException($"用户升级超级商人{month}个月余额不足！");

            walletService.ChangeChargeWallet(uid, -fee, fee, null, FinancialBizType.升级超级商人佣金, "升级超级商人", $"升级超级商人{month}个月支付");
            //升级操作
            var u = userRepository.GetByKey(uid);

            u.TraderLevel = TraderLevel.超级商家;

            TraderLevelLog traderLevelLog = new TraderLevelLog();
            traderLevelLog.CT = traderLevelLog.UT = DateTime.Now;
            traderLevelLog.TraderLevel = u.TraderLevel;
            traderLevelLog.PayMoney = fee;
            traderLevelLog.PayID = payID;
            traderLevelLog.Time = month;

            var lastLog = u.TraderLevelLogs.OrderByDescending(i => i.CT).FirstOrDefault();
            if (lastLog != null)
            {
                traderLevelLog.OutTime = lastLog.OutTime.AddMonths(month);

                u.TraderLevelLogs.Add(traderLevelLog);
            }
            else
            {
                traderLevelLog.OutTime = DateTime.Today.AddMonths(month).AddDays(1);

                u.TraderLevelLogs.Add(traderLevelLog);
            }

            //efUnitOfWork.Commit();

            return traderLevelLog;
        }

        public UserLevelLog PayUpLevelByUser(int uid, int month, int payID, int fee)
        {
            var wallet = walletRepository.Entities.FirstOrDefault(i => i.UserID == uid);
            if (wallet == null) throw new BizException($"未找到用户钱包！");


            if (wallet.ChargeBlance < fee) throw new BizException($"用户升级任务达人{month}个月余额不足！");

            walletService.ChangeChargeWallet(uid, -fee, fee, null, FinancialBizType.升级任务达人, "升级任务达人", $"升级任务达人{month}个月支付");
            //升级操作
            var u = userRepository.GetByKey(uid);

            u.UserLevel = UserLevel.任务达人;


            UserLevelLog userLevelLog = new UserLevelLog();
            userLevelLog.CT = userLevelLog.UT = DateTime.Now;
            userLevelLog.UserLevel = u.UserLevel;
            userLevelLog.PayMoney = fee;
            userLevelLog.PayID = payID;
            userLevelLog.Time = month;

            var lastLog = u.UserLevelLogs.OrderByDescending(i => i.CT).FirstOrDefault();
            if (lastLog != null)
            {
                userLevelLog.OutTime = lastLog.OutTime.AddMonths(month);

                u.UserLevelLogs.Add(userLevelLog);
            }
            else
            {
                userLevelLog.OutTime = DateTime.Today.AddMonths(month).AddDays(1);

                u.UserLevelLogs.Add(userLevelLog);
            }

            //efUnitOfWork.Commit();

            return userLevelLog;
        }
    }
}
